
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Derm.UnitTest
{
	/// <summary>
	/// Utility class for validating XML documents.
	/// </summary>
	class XmlValidator
	{
		public static void ValidateXmlSerialization(object xmlObject)
		{
			Type objectType = xmlObject.GetType();
			XmlSerializer objectSerializer = new XmlSerializer(objectType);

			using (MemoryStream xmlStream = new MemoryStream()) {
				// Serialize object in XML
				objectSerializer.Serialize(xmlStream, xmlObject);

				xmlStream.Seek(0, SeekOrigin.Begin);

				string xmlString = Encoding.UTF8.GetString(xmlStream.ToArray());

				// Load XSD
				XmlSchema dermSchema;

				sSchemaValidationError = false;
				sValidationLog.Remove(0, sValidationLog.Length);
				using (StreamReader sr = new StreamReader("../../../../../Derm/Xml/Schemas/Derm.xsd")) {
					dermSchema = XmlSchema.Read(sr, SchemaValidationEventHandler);
				}
				if (sSchemaValidationError == true)
					throw new InvalidOperationException(sValidationLog.ToString());


				// Validate XML object representation
				XmlReaderSettings settings = new XmlReaderSettings();
				settings.CloseInput = true;     
				settings.ValidationEventHandler += XmlValidationEventHandler;
				settings.ValidationType = ValidationType.Schema;
				settings.Schemas.Add(dermSchema);
				settings.ValidationFlags =
					XmlSchemaValidationFlags.ReportValidationWarnings |
					XmlSchemaValidationFlags.ProcessIdentityConstraints |
					XmlSchemaValidationFlags.ProcessInlineSchema |
					XmlSchemaValidationFlags.ProcessSchemaLocation;

				// Start from the beginning
				xmlStream.Seek(0, SeekOrigin.Begin);

				sXmlValidationError = false;
				sValidationLog.Remove(0, sValidationLog.Length);
				using (XmlReader validatingReader = XmlReader.Create(xmlStream, settings)) {
					while (validatingReader.Read()) { /* Validate elements */ }
				}
				if (sXmlValidationError == true)
					throw new InvalidOperationException(sValidationLog.ToString());
			}
		}

		private static void SchemaValidationEventHandler(object sender, ValidationEventArgs e)
		{
			sValidationLog.AppendFormat("{0}: {1}", e.Message, e.Exception);
			sValidationLog.AppendLine();
			sSchemaValidationError = true;
		}

		private static void XmlValidationEventHandler(object sender, ValidationEventArgs e)
		{
			sValidationLog.AppendFormat("{0}: {1}", e.Message, e.Exception);
			sValidationLog.AppendLine();
			sSchemaValidationError = true;
		}

		private static bool sSchemaValidationError;

		private static bool sXmlValidationError;

		private static readonly StringBuilder sValidationLog = new StringBuilder();
	}
}
